﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Lacrima.Framework.Infrastructure
{
    public static class Converter
    {
        public static IDictionary<string, string> ToDictionary<T>(T target)
        {
            Type type = typeof(T);
            FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
            PropertyInfo[] properties = type.GetProperties();
            IDictionary<string, string> dictionary = new Dictionary<string, string>();
            object value = null;
            for (int i = 0; i < fields.Length; ++i)
            {
                value = fields[i].GetValue(target);
                if (value != null && !string.IsNullOrEmpty(value.ToString().Trim()))
                {
                    dictionary.Add(properties[i].Name, value.ToString());
                }
                else
                {
                    dictionary.Add(properties[i].Name, string.Empty);
                }
            }
            return dictionary;
        }

        /// <summary>
        /// 将字符串转化为字节数组
        /// </summary>
        /// <param name="target"></param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static byte[] Text2Bytes(string target, string encode = "")
        {
            byte[] bytes;
            if (string.IsNullOrEmpty(encode))
            {
                bytes = Encoding.Default.GetBytes(target);
            }
            else
            {
                bytes = Encoding.GetEncoding(encode).GetBytes(target);
            }
            return bytes;
        }

        /// <summary>
        /// 将Aixm类型内存对象映射为实体对象
        /// </summary>
        /// <typeparam name="TResult">实体对象类型</typeparam>
        /// <typeparam name="TSource">内存对象类型</typeparam>
        /// <param name="source">需要被映射的内存对象</param>
        /// <returns>映射生成的实体对象</returns>
        public static TResult ReflectToEntity<TResult, TSource>(this TSource source)
            where TResult : class,new()
            where TSource : class
        {
            TResult result = new TResult();

            PropertyInfo[] sourceTypePropertyArray = source.GetType().GetProperties();
            PropertyInfo[] resultTypePropertyArray = result.GetType().GetProperties();

#if DEBUG
            string debugPropertyName = "not target";
#endif

            foreach (PropertyInfo resultProperty in resultTypePropertyArray)
            {
#if DEBUG
                // 用于调试特殊字段时使用
                if (resultProperty.Name.Equals(debugPropertyName, StringComparison.OrdinalIgnoreCase))
                {
                    Debug.WriteLine(debugPropertyName);
                }
#endif
                // 数据表字段与内存对象属性通过名称匹配
                if (sourceTypePropertyArray.Any(o => o.Name.Equals(resultProperty.Name, StringComparison.OrdinalIgnoreCase))
                    && ReflectionUtil.ignoreProperties.All(n => !n.Equals(resultProperty.Name, StringComparison.OrdinalIgnoreCase)))
                {
                    // 获取节点属性
                    PropertyInfo sourceProperty = sourceTypePropertyArray.Single(o => o.Name.Equals(resultProperty.Name, StringComparison.OrdinalIgnoreCase));
                    // 获取节点对象值
                    var subSourceObject = sourceProperty.GetValue(source);

                    // 解析基本类型
                    // 判断该类型是否与列表中的类型相符合或者是其扩展类
                    if (sourceProperty.PropertyType.IsValueType || sourceProperty.PropertyType.IsEquivalentTo(typeof(string)))
                    {
                        source.SetValueByProperty(sourceProperty, result, resultProperty);
                    }
                    else if (subSourceObject != null)
                    {
                        // 处理数组类型变量
                        if (typeof(Array).IsAssignableFrom(sourceProperty.PropertyType))
                        {
                            // 示例：解析name字段信息
                            subSourceObject.SetValueByProperty(sourceProperty, result, resultProperty);
                        }
                        else
                        {
                            // 解析自定义类型所包含的属性信息
                            PropertyInfo[] subTypePropertyArray = sourceProperty.PropertyType.GetProperties();

                            // 处理自定义类型变量，包括特殊类型和一般类型
                            if (ReflectionUtil.specialTypeDictionary.Any(o => o.Key.IsTypeIn(sourceProperty.PropertyType, subSourceObject.GetType())))
                            {
                                Type subSpecialType = ReflectionUtil.specialTypeDictionary.Where(o => o.Key.IsTypeIn(sourceProperty.PropertyType, subSourceObject.GetType()))
                                                                                                     .Select(o => o.Value)
                                                                                                     .Single();
                                object subSpecialPropertyObject = null;

                                // 解析外键关联关系表的内存对象
                                //if (typeof(AbstractGMLType).IsAssignableFrom(subSpecialType))
                                //{
                                //    var subSpecialObject = subSourceObject.GetValueByProperty(o => typeof(AbstractGMLType).IsAssignableFrom(o.PropertyType)) as AbstractGMLType;
                                //    subSpecialPropertyObject = subSpecialObject == null ? null : subSpecialObject.id;
                                //}
                                //else if (typeof(TimePositionType).IsAssignableFrom(subSpecialType))
                                //{
                                //    subSpecialPropertyObject = subSourceObject.GetDefaultValue();
                                //}
                                //else if (typeof(****).IsAssignableFrom(subSpecialType))
                                //{
                                //    //此处添加特殊类型的处理方法
                                //    subSpecialPropertyObject = ****;
                                //}
                                // 如果subSpecialPropertyObject为空的话返回result对象中resultProperty属性的值
                                resultProperty.SetValue(result, Convert.ChangeType(subSpecialPropertyObject ?? resultProperty.GetValue(result), resultProperty.PropertyType));
                            }
                            else if (subTypePropertyArray.Any(n => ReflectionUtil.validProperties.Contains(n.Name, StringComparer.OrdinalIgnoreCase)))
                            {
                                // 获取自定义类中的合法字段列表并遍历将值赋值给实体类
                                PropertyInfo[] subTypeValidProperties = subTypePropertyArray.Where(o => ReflectionUtil.validProperties.Contains(o.Name, StringComparer.OrdinalIgnoreCase)).ToArray();
                                foreach (PropertyInfo property in subTypeValidProperties)
                                {
                                    subSourceObject.SetValueByProperty(property, result, resultProperty);
                                }
                            }
                        }
                    }
                }
                else if (ReflectionUtil.trunkSpecialPropertyDictionary.Any(o => o.Key.Equals(resultProperty.Name, StringComparison.OrdinalIgnoreCase)))
                {
                    // 此处的实体类字段信息与内存对象字段信息不匹配，通过名称或者类型进行解析，例如：解析经纬度字段
                    PropertyInfo sourceTrunkProperty = sourceTypePropertyArray.SingleOrDefault(ReflectionUtil.trunkSpecialPropertyDictionary[resultProperty.Name]);
                    if (sourceTrunkProperty == null)
                    {
                        // 类型属性信息中不包含字典中的匹配字段信息，试着解析其子类信息
                        //if (sourceTypePropertyArray.Any(o => typeof(DirectPositionType).IsAssignableFrom(o.PropertyType) || typeof(AbstractGeometryType).IsAssignableFrom(o.PropertyType)))
                        //{
                        //    sourceTrunkProperty = sourceTypePropertyArray.SingleOrDefault(o => typeof(DirectPositionType).IsAssignableFrom(o.PropertyType)
                        //                                                                                                                || typeof(AbstractGeometryType).IsAssignableFrom(o.PropertyType));
                        //    var sourceTrunkObject = source.GetValueByProperty(sourceTrunkProperty);
                        //    sourceTrunkProperty = sourceTrunkObject.GetType().GetProperties().Single(ReflectionUtil.trunkSpecialPropertyDictionary[resultProperty.Name]);
                        //    sourceTrunkObject.SetValueByProperty(sourceTrunkProperty, result, resultProperty);
                        //}
                    }
                    else
                        source.SetValueByProperty(sourceTrunkProperty, result, resultProperty);
                }
            }

            // 判断内存对象是否解析成功，如果没有解析成功的话尝试解析其成员变量
            bool sourceNotContainsId = sourceTypePropertyArray.All(o => !o.Name.Equals("id", StringComparison.OrdinalIgnoreCase));
            bool resultContainsNullId = result.GetValueByProperty(o => o.Name.Equals("id", StringComparison.OrdinalIgnoreCase)) == null;
            if (sourceNotContainsId && resultContainsNullId)
            {
                // 解析成员变量中有效类型，例如时间日期类型：TimePeriodType
                //if (sourceTypePropertyArray.Any(o => typeof(AbstractGMLType).IsAssignableFrom(o.PropertyType)))
                //{
                //    // 此处解析包含外键表基本信息的类型，例如该类型中包含id，identifer之类的字段信息等等
                //    // 获取节点对象值
                //    var subSourceObject = source.GetValueByProperty(o => typeof(AbstractGMLType).IsAssignableFrom(o.PropertyType));
                //    if ((subSourceObject as TimePeriodType) != null)
                //    {
                //        // 解析TimePrimitivePropertyType类型内存对象
                //        result = (subSourceObject as TimePeriodType).ReflectToEntity<TResult, TimePeriodType>();
                //    }
                //    else if ((subSourceObject as ElevatedPointType) != null)
                //    {
                //        // 解析ElevatedPointPropertyType类型内存对象
                //        result = (subSourceObject as ElevatedPointType).ReflectToEntity<TResult, ElevatedPointType>();
                //    }
                //    //else if ((subSourceObject as ****) != null)
                //    //{
                //    //    // 解析****类型内存对象
                //    //    result = (subSourceObject as ****).ReflectToEntity<TResult, ****>();
                //    //}
                //}
            }

            return result;
        }


        /// <summary>
        /// 通过实体对象和内存对象生成对应的关系表实体对象
        /// </summary>
        /// <typeparam name="TMaster">主表实体类型</typeparam>
        /// <typeparam name="TSlave">外键关联表对应的内存对象类型</typeparam>
        /// <typeparam name="TRelation">关系表实体类型</typeparam>
        /// <param name="master">主表实体对象</param>
        /// <param name="slave">外键关联表对应的内存对象</param>
        /// <returns>关系表实体对象</returns>
        public static TRelation ReflectToRelationEntity<TMaster, TSlave, TRelation>(this TMaster master, TSlave slave)
            where TRelation : class,new()
            where TMaster : class
            where TSlave : class
        {
            TRelation relation = new TRelation();

            Type masterType = master.GetType();
            Type slaveType = slave.GetType();
            Type relationType = relation.GetType();
            string relationMasterColumnName = string.Format("{0}_id", masterType.Name);
            string relationSlaveColumnName = string.Format("{0}_id", slaveType.Name.Remove(slaveType.Name.IndexOf("PropertyType")));

            //bool containsSlaveSubObject = slaveType.GetProperties().Any(o => typeof(AbstractGMLType).IsAssignableFrom(o.PropertyType));
            //master.SetValueByProperty(null, o => o.Name.Equals("id", StringComparison.OrdinalIgnoreCase), relation, null, o => o.Name.Equals(relationMasterColumnName, StringComparison.OrdinalIgnoreCase));
            //if (containsSlaveSubObject)
            //{
            //    var slaveSubObject = slave.GetValueByProperty(o => typeof(AbstractGMLType).IsAssignableFrom(o.PropertyType)) as AbstractGMLType;
            //    var id = slaveSubObject.id;
            //    PropertyInfo relationProperty = relationType.GetProperties().Single(o => o.Name.Equals(relationSlaveColumnName, StringComparison.OrdinalIgnoreCase));
            //    relationProperty.SetValue(relation, id);
            //}
            //else
            //{
            //    slave.SetValueByProperty(null, o => o.Name.Equals("id", StringComparison.OrdinalIgnoreCase), relation, null, o => o.Name.Equals(relationSlaveColumnName, StringComparison.OrdinalIgnoreCase));
            //}

            return relation;
        }

    }
}
